unit GLGUISkin;

interface

{$I GLScene.inc}

uses
  Dialogs,
  Classes,
  SysUtils,
  VectorGeometry,
  GLTexture,
  GLGUIState,
  GLSCrossXML,
  GLSGenerics,
  GLS_Material,
  GLGUITokens,
  GLGUIKeys;

type
  TGLGUICustomSkin = class;
  TGLGUIBasicSkin = class;
  TGLGUIBasicStateDescriptor = class;
  TGLGUIStatesList = GList<TGLGUICustomStateDescriptor>;
  TGLGUISkinClass = class of TGLGUICustomSkin;
  TGLGUICustomSkinsList = GList < TGLGUICustomSkin >;

  TGLGUIBasicStateDescriptor = class(TGLGUICustomStateDescriptor)
  private
    FSkin: TGLGUIBasicSkin;
    function GetStateSkin: TGLGUIBasicSkin;
    procedure SetStateSkin(ASkin: TGLGUIBasicSkin);
  public
    constructor Create(AType: String); override;
    procedure Parse; override;
    property StateSkin: TGLGUIBasicSkin read GetStateSkin write SetStateSkin;
    destructor Destroy(); override;
  end;

  TGLGUICustomSkin = class
  protected
    FName: String;
    FType: String;
    FTexture: TGLTextureImageEx;
    FTextureWidth: Integer;
    FTextureHeight: Integer;
    FXMLNode: GLSXMLNode;
    FStates: TGLGUIStatesList;
    FKeys: TGLGUIKeysList;
    FIsParsed: Boolean;
    function GetName: String; virtual;
    function GetType: String; virtual;
    function GetTexture: TGLTextureImageEx; virtual;
    function GetIsParsed: Boolean;
    procedure SetName(AName: String); virtual;
    procedure SetType(AType: String); virtual;
    procedure SetTexture(ATexture: TGLTextureImageEx); virtual;
    function GetKey(AIndex: String): TGLGUIKey;
  public
    constructor Create; virtual;
    procedure Parse; virtual;
    procedure Assign(const ASkin: TGLGUICustomSkin; const AAssignStates: Boolean = False); virtual;
    procedure AddKey(AKey: TGLGUIKey); virtual;
    destructor Destroy(); override;
    property Name: String read GetName write SetName;
    property SkinType: String read GetType write SetType;
    property Texture: TGLTextureImageEx read GetTexture write SetTexture;
    property IsParsed: Boolean read GetIsParsed;
    property Key[AIndex: String]: TGLGUIKey read GetKey;
    property TextureWidth: Integer read FTextureWidth;
    property TextureHeight: Integer read FTextureHeight;
  end;

  TGLGUIBasicSkin = class(TGLGUICustomSkin)
  private
    FOffset: TVector;
    function GetOffset: TVector;
    procedure SetOfset(AOffset: TVector);
    function GetStateDescription(AState: TGLGUIState): TGLGUIBasicStateDescriptor;
  public
    procedure Parse; override;
    procedure Assign(const ASkin: TGLGUICustomSkin; const AAssignStates: Boolean = False); override;
    procedure AddState(AState: TGLGUIBasicStateDescriptor);
    property StateDescription[AState: TGLGUIState]: TGLGUIBasicStateDescriptor read GetStateDescription;
    property Offset: TVector read GetOffset write SetOfset;
  end;

  TGLGUIBasicSkinsList = GList < TGLGUIBasicSkin >;

implementation

uses
  GLGUISkinManager, GLGUIUtils;

type
  TGLGUICustomStateDescriptorAccessProvider = class(TGLGUICustomStateDescriptor);

{$IFDEF GLS_REGIONES}{$REGION 'State'}{$ENDIF}

constructor TGLGUIBasicStateDescriptor.Create(AType: String);
begin
  inherited;
  FSkin := TGLGUIBasicSkin.Create;
end;

procedure TGLGUIBasicStateDescriptor.Parse;
var
  i: Integer;
  vCurentStateElement: GLSXMLNode;
  vTemporarySkin: TGLGUIBasicSkin;
  vStateType: String;
  vStateValue: String;
begin
  if FXMLNode = nil then
    Exit;
  vCurentStateElement := FXMLNode.ChildNodes.Get(0);
  GetXMLAttribute(vCurentStateElement, 'Type', vStateType);
  if vStateType = 'Skin' then
  begin
    GetXMLAttribute(vCurentStateElement, 'Value', vStateValue);
    with GUISkinManager do
      vTemporarySkin := TGLGUIBasicSkin(GetSkinByName(vStateValue));
    if not vTemporarySkin.IsParsed then
      vTemporarySkin.Parse;
    StateSkin.Assign(vTemporarySkin);
    FIsParsed := True;
    Exit;
  end
  else
  begin
    for i := 0 to FXMLNode.ChildNodes.Count - 1 do
    begin
      vCurentStateElement := FXMLNode.ChildNodes.Get(i);
      with vCurentStateElement do
        begin
          GetXMLAttribute(vCurentStateElement, 'Type', vStateType);
          GetXMLAttribute(vCurentStateElement, 'Value', vStateValue);
          if vStateType = 'Offset' then
            StateSkin.FOffset := StringToVector4f(vStateValue);
        end;
    end;
    FIsParsed := True;
  end;
end;

function TGLGUIBasicStateDescriptor.GetStateSkin: TGLGUIBasicSkin;
begin
  Result := FSkin;
end;

procedure TGLGUIBasicStateDescriptor.SetStateSkin(ASkin: TGLGUIBasicSkin);
begin
  FSkin := ASkin;
end;

destructor TGLGUIBasicStateDescriptor.Destroy();
begin
  FSkin.Free;
  inherited;
end;

{$IFDEF GLS_REGIONES}{$ENDREGION}{$ENDIF}

{$IFDEF GLS_REGIONES}{$REGION 'TGLGUICustomSkin'}{$ENDIF}

constructor TGLGUICustomSkin.Create;
begin
  FStates := TGLGUIStatesList.Create;
  FKeys := TGLGUIKeysList.Create;
end;

procedure TGLGUICustomSkin.Parse;
begin
end;

procedure TGLGUICustomSkin.Assign(const ASkin: TGLGUICustomSkin; const AAssignStates: Boolean = False);
begin
  FName := ASkin.FName;
  FType := ASkin.FType;
  FTexture := ASkin.FTexture;
  FXMLNode := ASkin.FXMLNode;
end;

procedure TGLGUICustomSkin.AddKey(AKey: TGLGUIKey);
begin
  if not Assigned(FKeys) then
    FKeys := TGLGUIKeysList.Create;
  FKeys.Add(AKey);
end;

function TGLGUICustomSkin.GetName: String;
begin
  Result := FName;
end;

function TGLGUICustomSkin.GetType: String;
begin
  Result := FType;
end;

function TGLGUICustomSkin.GetTexture: TGLTextureImageEx;
begin
  Result := FTexture;
end;

function TGLGUICustomSkin.GetIsParsed: Boolean;
begin
  Result := FIsParsed;
end;

procedure TGLGUICustomSkin.SetName(AName: String);
begin
  FName := AName;
end;

procedure TGLGUICustomSkin.SetType(AType: String);
begin
  FType := AType;
end;

procedure TGLGUICustomSkin.SetTexture(ATexture: TGLTextureImageEx);
begin
  FTexture := ATexture;
end;

function TGLGUICustomSkin.GetKey(AIndex: String): TGLGUIKey;
begin
  Result := FKeys.Find(AIndex);
end;

destructor TGLGUICustomSkin.Destroy();
var
  i: Integer;
begin
  for i := 0 to FKeys.Count - 1 do
    FKeys[i].Free;
  FKeys.Free;
  for i := 0 to FStates.Count - 1 do
    FStates[i].Free;
  FStates.Free;
  inherited;
end;

{$IFDEF GLS_REGIONES}{$ENDREGION}{$ENDIF}

{$IFDEF GLS_REGIONES}{$REGION 'TGLGUIBasicSkin'}{$ENDIF}

procedure TGLGUIBasicSkin.Parse;
var
  i: Integer;
  CurentSkinElement: GLSXMLNode;
  vState: TGLGUIBasicStateDescriptor;
  vStateType: String;
begin
  if FXMLNode = nil then
    Exit;

  if FStates = nil then
    FStates := TGLGUIStatesList.Create
  else
  begin
    for I := 0 to FStates.Count - 1 do
      FStates.Items[i].Free;
      FStates.Clear;
  end;

  for i := 0 to FXMLNode.ChildNodes.Count - 1 do
  begin
    CurentSkinElement := FXMLNode.ChildNodes.Get(i);
    if CurentSkinElement.LocalName = 'SkinElement' then
      FOffset := StringToVector4f(CurentSkinElement.Attributes['Offset']);
    if CurentSkinElement.LocalName = 'State' then
    begin
       GetXMLAttribute(CurentSkinElement, 'Type', vStateType);
       vState := TGLGUIBasicStateDescriptor.Create(vStateType);
       TGLGUICustomStateDescriptorAccessProvider(vState).FXMLNode := CurentSkinElement;
       AddState(vState);
    end;
  end;

  FIsParsed := True;
end;

procedure TGLGUIBasicSkin.Assign(const ASkin: TGLGUICustomSkin; const AAssignStates: Boolean = False);
begin
  if ASkin is TGLGUIBasicSkin then
    FOffset := TGLGUIBasicSkin(ASkin).Offset;
  inherited Assign(ASkin);
end;

procedure TGLGUIBasicSkin.AddState(AState: TGLGUIBasicStateDescriptor);
begin
  AState.StateSkin.Assign(Self);
  if not AState.IsParsed then
    AState.Parse;
  FStates.Add(AState);
end;

function TGLGUIBasicSkin.GetOffset: TVector;
begin
  Result := FOffset;
end;

procedure TGLGUIBasicSkin.SetOfset(AOffset: TVector);
begin
  FOffset[0] := AOffset[0];
  FOffset[1] := AOffset[1];
  FOffset[2] := AOffset[2];
  FOffset[3] := AOffset[3];
end;

function TGLGUIBasicSkin.GetStateDescription(AState: TGLGUIState): TGLGUIBasicStateDescriptor;
var
  i: Integer;
begin
  Result := nil;
  for i := 0 to FStates.Count - 1 do
    if FStates.Items[i].State = AState then
    begin
      Result := TGLGUIBasicStateDescriptor(FStates.Items[i]);
      Exit;
    end;
end;

{$IFDEF GLS_REGIONES}{$ENDREGION}{$ENDIF}

initialization
  RegisterSkin(TGLGUIBasicSkin);

finalization

end.
